#pragma once

#include <fstream>
using std::ifstream;
#include <stdexcept>
using std::exception;
using std::runtime_error;
#include <unordered_map>
using std::unordered_map;

#include "Common.h"
#include "ShaderObject.h"

namespace davrenderer { class Shader; }
using namespace davrenderer;

// TODO : [Unordered_]Map of shader params so we don't have to keep asking opengl to get them?

/* * * * * * * * * *
 * Shader
 * Author:	David Ogle
 * Date:	04/04/2012
 * Encapsulation of an entire shader program, e.g.
 * a Vertex, Fragment and optional Geometry shaders.
 * * * * * * * * * */
class davrenderer::Shader
{
friend class ShaderObject;
private:

	Shader(Shader &copy) { };	// Hide the copy constructor

protected:

	bool init;
	GLuint			program;
	ShaderObject	*vertex;
	ShaderObject	*fragment;
	ShaderObject	*geometry;

public:

	static Shader* FromFiles(ifstream &vert, ifstream &frag);
	static Shader* FromFiles(ifstream &vert, ifstream &frag, ifstream &geom);
	static Shader* FromStrings(string vert, string frag, string geom = "");
	static Shader* FromFilenames(string vert, string frag, string geom = "");


	Shader(void);	// TODO : This should be private?
	~Shader(void);


	void linkProgram();


	// Add shader objects
	void addShaderObject(string s, GLenum type, bool isFilename = true);
	void addShaderObject(ifstream &s, GLenum type);
	void addVertexShader(string vert, bool isFilename = true)		{ addShaderObject(vert, GL_VERTEX_SHADER, isFilename); }
	void addVertexShader(ifstream &vert)							{ addShaderObject(vert, GL_VERTEX_SHADER); }
	void addFragmentShader(string frag, bool isFilename = true)		{ addShaderObject(frag, GL_FRAGMENT_SHADER, isFilename); }
	void addFragmentShader(ifstream &frag)							{ addShaderObject(frag, GL_FRAGMENT_SHADER); }
	void addGeometryShader(string geom, bool isFilename = true)		{ addShaderObject(geom, GL_GEOMETRY_SHADER, isFilename); }
	void addGeometryShader(ifstream &geom)							{ addShaderObject(geom, GL_GEOMETRY_SHADER); }
	
};

